package page.mainPage;

import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.stage.Popup;
import javafx.stage.Window;

import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 自定提示控件
 * <p>
 * 根据输入的内容和提示列表来匹配提示信息<br/>
 * </p>
 */
public class AutoCompleteTextField {
    private final static int LIST_MAX_SIZE = 6;
    private final static int LIST_CELL_HEIGHT = 24;
    private final TextField textField;
    /**
     * 用来存储显示 出来的信息列表
     */
    private final ObservableList<String> showCacheDataList = FXCollections.observableArrayList();
    /**
     * 监听输入框的内容
     */
    private final SimpleStringProperty inputContent = new SimpleStringProperty();

    /**
     * <p>
     * 显示pop
     * </p>
     */
    public final void showTipPop() {
        autoTipList.setPrefWidth(textField.getWidth() - 3);
        if (showCacheDataList.size() < LIST_MAX_SIZE) {
            autoTipList.setPrefHeight(showCacheDataList.size() * LIST_CELL_HEIGHT + 3);
        } else {
            autoTipList.setPrefHeight(LIST_MAX_SIZE * LIST_CELL_HEIGHT + 3);
        }
        Window window = getWindow();
        // 窗口被突然移除了，比如打开一个新窗口，旧窗口不在了
        if (window == null) {
            return;
        }
        Scene scene = getScene();
        Point2D fieldPosition = textField.localToScene(0, 0);
        // x 与 textfield 位置一致，y 在 textfield 下面
        popShowList.show(window, window.getX() + fieldPosition.getX() + scene.getX(), window.getY() + fieldPosition.getY() + scene.getY() + textField.getHeight());
        autoTipList.getSelectionModel().clearSelection();
        autoTipList.getFocusModel().focus(-1);
    }

    /**
     * 用来存储缓存的信息列表 重写indexOf方法来获取匹配到的数据
     */
    private final List<String> cacheDataList = new ArrayList<>() {
        @Serial
        private static final long serialVersionUID = 281687373227150590L;

        // 输入内容时进行筛选
        @Override
        public int indexOf(Object searchContext) {
            showCacheDataList.clear();
            if (null == searchContext || searchContext.toString().equals("")) {
                return -1;
            }
            for (String s : cacheDataList) {
                if (s.toLowerCase().contains(searchContext.toString().toLowerCase())) {
                    showCacheDataList.add(s);
                }
            }
            return -1;
        }
    };
    /**
     * 输入内容后显示的pop
     */
    private final Popup popShowList = new Popup();
    /**
     * 输入内容后显示的提示信息列表
     */
    private final ListView<String> autoTipList = new ListView<>();

    AutoCompleteTextField(TextField textField, List<String> cacheDataList, Consumer<String> selectedFunction) {
        if (null == textField) {
            throw new RuntimeException("textField 不能为空");
        }
        this.textField = textField;
        if (null != cacheDataList) {
            this.cacheDataList.addAll(cacheDataList);
        }
        configure();
        confListnenr(selectedFunction);
    }

    public void closePopShowList() {
        if (popShowList.isShowing()) {
            popShowList.hide();
        }
    }

    /**
     * <p>
     * 添加监听事件
     * </p>
     */
    private void confListnenr(Consumer<String> selectedFunction) {
        textField.textProperty().bindBidirectional(inputContent);
        inputContent.addListener((obs, oldValue, newValue) -> {
            // 输入 / 时，展开下拉菜单，并显示所有内容
            if (newValue.endsWith("/")) {
                showCacheDataList.clear();
                showCacheDataList.addAll(cacheDataList);
                showTipPop();
            }
            // 如果下拉菜单被打开，会根据输入内容对菜单进行过滤
            else if (popShowList.isShowing()) {
                // 取出最后一段以 / 开头的内容
                String[] split = newValue.split("/");
                String tipContent = split[split.length - 1];
                configureListContext(tipContent);    //当文本框中内容发生变化时会触发此事件，对文本框中内容进行匹配
            }

        });

        autoTipList.setOnMouseClicked(event -> selectedItem(selectedFunction));

        autoTipList.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.ENTER) {
                selectedItem(selectedFunction);
            }
        });
    }

    /**
     * <p>
     * 获取选中的list内容到输入框
     * </p>
     */
    private void selectedItem(Consumer<String> selectedFunction) {
        String input = autoTipList.getSelectionModel().getSelectedItem();
        inputContent.set(input);
        selectedFunction.accept(input);
        textField.end();
        popShowList.hide();
    }

    /**
     * <p>
     * 根据输入的内容来配置提示信息
     * </p>
     */
    private void configureListContext(String tipContent) {
        cacheDataList.indexOf(tipContent);
        if (!showCacheDataList.isEmpty()) {
            showTipPop();
        } else {
            popShowList.hide();
        }
    }

    /**
     * <p>
     * 配置组建
     * </p>
     */
    private void configure() {
        popShowList.setAutoHide(true);
        popShowList.getContent().add(autoTipList);
        autoTipList.setItems(showCacheDataList);
    }


    /**
     * <p>
     * 获取pop显示的窗口
     * </p>
     */
    public final Window getWindow() {
        // 窗口被删除
        if (getScene() == null) {
            return null;
        }
        return getScene().getWindow();
    }

    /**
     * <p>
     * 获取textField Scene
     * </p>
     */
    public final Scene getScene() {
        return textField.getScene();
    }


}
